package com.nescafe.nescafepromo.command.admin;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.nescafe.nescafepromo.command.Command;
import com.nescafe.nescafepromo.command.CommandException;
import com.nescafe.nescafepromo.entity.EntityType;
import com.nescafe.nescafepromo.entity.Participant;
import com.nescafe.nescafepromo.entity.TotalPoints;
import com.nescafe.nescafepromo.model.NPRequest;
import com.nescafe.nescafepromo.model.NPResponse;
import com.nescafe.nescafepromo.model.ParticipantDetailList;

public class DrawWinners implements Command {

	@Override
	public NPResponse execute(NPRequest req) throws CommandException {
		NPResponse res = null;
		try {
			int drawcount = 1;
			try {
				drawcount = Integer.parseInt(req.getParam("drawcount"));
			} catch (Exception e) {
			}
			ParticipantDetailList pdList = new ParticipantDetailList();
			DatastoreService ds = DatastoreServiceFactory.getDatastoreService();

			Query q = new Query(EntityType.TOTAL_POINTS.getKind());
			q.addSort(TotalPoints.TOTAL_POINTS_FIELD, SortDirection.DESCENDING);
			PreparedQuery pq = ds.prepare(q);
			List<Entity> points = pq.asList(FetchOptions.Builder.withLimit(500));
			Collections.shuffle(points);

			double totalEntryPoints = 0.0d;
			List<TotalPoints> tpList = new ArrayList<TotalPoints>();
			for (Entity entity : points) {
				try {
					TotalPoints tp = new TotalPoints(entity);
					totalEntryPoints += tp.getTotalPonts();

					tpList.add(tp);
				} catch (Exception e) {
				}
			}
			double random = Math.random() * totalEntryPoints;
			List<TotalPoints> winnerPoints = new ArrayList<TotalPoints>();

			for (TotalPoints tPoints : tpList) {
				random -= tPoints.getTotalPonts();
				if (random <= 0.0d) {
					tPoints.getParent();
					winnerPoints.add(tPoints);
					if (winnerPoints.size() >= drawcount) {
						break;
					}
				}
			}

			List<Key> participantKeys = new ArrayList<Key>();
			for (TotalPoints tPoints : winnerPoints) {
				participantKeys.add(tPoints.getParent());
			}

			q = new Query(EntityType.PARTICIPANT.getKind());
			q.addFilter(Entity.KEY_RESERVED_PROPERTY, FilterOperator.IN, participantKeys);
			pq = ds.prepare(q);
			List<Entity> winners = pq.asList(FetchOptions.Builder.withLimit(drawcount));

			for (Entity e : winners) {
				pdList.addParticiPant(new Participant(e));
			}

			for (TotalPoints tp : winnerPoints) {
				pdList.addTotalPoints(tp);
			}

			res = new NPResponse(pdList);

		} catch (Exception e) {
			throw new CommandException(e.getMessage());
		}
		return res;
	}
}
